import "./style.css";

/**
 * 创建动画图表解析函数
 * @param XAxisStart - 起始点的X轴坐标
 * @param XAxisEnd - 终止点的X轴坐标
 * @param YAxisStart - 起始点的Y轴坐标
 * @param YAxisEnd - 终止点的Y轴坐标
 * @returns 返回动画曲线的解析函数，函数输入自变量，返回对应坐标值
 */
const createAnimationDiagramFn = (XAxisStart: number, XAxisEnd: number, YAxisStart: number, YAxisEnd: number) => {
    return function (value: number) {
        // 取值范围和值域限制
        if (value < XAxisStart) return YAxisStart;
        if (value > XAxisEnd) return YAxisEnd;

        // 这里函数曲线为线性函数（如有必要可以整成贝塞尔曲线一样的曲线函数映射关系）
        const progress = (value - XAxisStart) / (XAxisEnd - XAxisStart);
        return YAxisStart + (YAxisEnd - YAxisStart) * progress;
    };
};

function randomColor() {
    const colors = [
        "#FFC0CB",
        "#FFA07A",
        "#FFD700",
        "#ADFF2F",
        "#87CEFA",
        "#00BFFF",
        "#00CED1",
        "#1E90FF",
        "#B0C4DE",
        "#FF69B4"
    ];
    return colors[Math.floor(Math.random() * colors.length)];
}

const animationContainer = document.querySelector(".animation-container") as HTMLElement;
const animationViewport = document.querySelector(".animation-viewport") as HTMLElement;
const listEL = document.querySelector(".list") as HTMLElement;
const itemEls = document.querySelectorAll(".list-item") as NodeListOf<HTMLElement>;

const xAxisStart = animationViewport.offsetTop - animationViewport.offsetHeight / 3;
const xAxisEnd =
    xAxisStart + animationContainer.offsetHeight - animationViewport.offsetHeight - animationViewport.offsetHeight / 4;

const createElementAnimationStatusObj = (
    itemEl: HTMLElement,
    listEl: HTMLElement,
    xAxisStart: number,
    xAxisEnd: number
): MapValue => {
    // 给元素设置随机颜色
    itemEl.style.backgroundColor = randomColor();

    // 设置动画延迟
    const delay: number = (itemEl.dataset.delay && 200 * +itemEl.dataset.delay) || 0;
    xAxisStart += delay;

    // 1.1 透明度变化的动画曲线图
    const opacityAnimationFn = createAnimationDiagramFn(xAxisStart, xAxisEnd, 0.5, 1);

    // 1.2 透明度包装函数，实时返回当前透明度
    const opacity = (currentXAxis: number) => {
        return opacityAnimationFn(currentXAxis);
    };

    // 3.0 大小变化动画状态函数
    const scaleAnimationFn = createAnimationDiagramFn(xAxisStart, xAxisEnd, 0.5, 1);

    // 3.1 计算初始位移。位移到中心点
    // （ currentX 实际是从 0 开始的，只是在取值范围外取的是两端的最值，所以不用单独应用计算出的位移值，设置 style 位移到中心点）
    const listELRect = listEl.getBoundingClientRect();
    const { left, top, width, height } = itemEl.getBoundingClientRect();
    const centerX = listELRect.left + listELRect.width / 2 - width / 2 - left;
    const centerY = listELRect.top + listELRect.height / 2 - height / 2 - top;

    // 3.2 位置变化动画状态函数
    const translateXAnimationFn = createAnimationDiagramFn(xAxisStart, xAxisEnd, centerX, 0);
    const translateYAnimationFn = createAnimationDiagramFn(xAxisStart, xAxisEnd, centerY, 0);

    // 3.3 transform 包装函数，实时返回当前 scale 和 translate 值
    const transform = (currentXAxis: number) => {
        return `translate(${translateXAnimationFn(currentXAxis * 1.2)}px, ${translateYAnimationFn(
            currentXAxis * 1.2
        )}px) scale(${scaleAnimationFn(currentXAxis)})`;
    };

    return {
        opacity,
        transform
    };
};

type MapValue = Partial<Record<keyof CSSStyleDeclaration, (currentXAxis: number) => string | number>>;
const styleStatusMap = new Map<HTMLElement, MapValue>();

const setMap = () => {
    for (const itemEl of itemEls) {
        styleStatusMap.set(itemEl, createElementAnimationStatusObj(itemEl, listEL, xAxisStart, xAxisEnd));
    }
};
setMap();

// 从 Map 中取出元素，并根据变化的 x 轴值，设置它的实时状态
const updateStyles = (currentXAxis: number, styleStatusMap: Map<HTMLElement, MapValue>) => {
    for (const [element, statusObj] of styleStatusMap) {
        for (const cssProperty in statusObj) {
            const getCurrentStatus = statusObj[cssProperty] as Function;
            element.style[cssProperty] = `${getCurrentStatus(currentXAxis)}`;
        }
    }
};

// 滚动驱动 x 轴变化
document.addEventListener("scroll", () => {
    updateStyles(document.documentElement.scrollTop, styleStatusMap);
});
